#include "reduced_grammar.h"

void eliminationLeftRecursion(const std::vector<Rules> &in, std::vector<Rules> &out)
{
    Rules rule = in[0];
    for (int i = 0, id = 0; i < in.size();) {
        out.push_back(Rules(rule.getNTSymbol(), ++id));
        std::vector<std::string> tmp_rules; // зберігаємо правила, які не мають лівої рекурсії
        for (int j = 0; j < rule.size(); j++) {
            std::string nt_symbol; // зчитуємо NT-символ на початку правила
            std::string specific_rule = rule.getRule(j);
            for (int z = 0; z < specific_rule.size(); z++) {
                if (!isupper(specific_rule[z])) break;
                nt_symbol += specific_rule[z];
            }
            if ((rule.getNTSymbol() == nt_symbol) && (out.back().getNTSymbol() == nt_symbol)) // перше ліворекурсивне правило для даного NT-символа
                out.push_back(Rules(nt_symbol + '1', ++id));
            if (rule.getNTSymbol() == nt_symbol) // ліворекурсивне правило
            {
                out[out.size() - 1].pushRule(specific_rule.substr(nt_symbol.size(), specific_rule.size() - nt_symbol.size()));
                out[out.size() - 1].pushRule(specific_rule.substr(nt_symbol.size(), specific_rule.size() - nt_symbol.size()) + " " + nt_symbol + '1');
            }
            else // неліворекурсивне правило
            {
                tmp_rules.push_back(specific_rule);
                tmp_rules.push_back(specific_rule + " " + rule.getNTSymbol() + '1');
            }
        }
        if (rule.getNTSymbol() == out[out.size() - 1].getNTSymbol()) // nt-символ не містить правил з лівою рекурсією
            for (int j = 0; j < rule.size(); j++)
                out[out.size() - 1].pushRule(rule.getRule(j));
        else if (rule.getNTSymbol() == out[out.size() - 2].getNTSymbol())// правила, які не містять лівої рекурсії
            for (int j = 0; j < tmp_rules.size(); j++)
                out[out.size() - 2].pushRule(tmp_rules[j]);
        rule.clear();
        if (i < (in.size() - 1)) ++i;
        else break;
        rule.setNTSymbol(in[i].getNTSymbol());
        for (int j = 0; j < in[i].size(); j++) { //крок 4
            std::string nt_symbol;
            for (int z = 0; z < in[i].getRule(j).size(); z++) {
                if (!isupper(in[i].getRule(j)[z])) break;
                nt_symbol += in[i].getRule(j)[z];
            }
            std::vector<Rules>::const_iterator it = std::find_if(out.begin(), out.end(), FindNTNumberId<Rules>(nt_symbol));
            if (it != out.end())
                for (int z = 1; z < it->size(); z++)
                    rule.pushRule(it->getRule(z) + in[i].getRule(j).substr(nt_symbol.size(), in[i].getRule(j).size() - nt_symbol.size()));
            else rule.pushRule(in[i].getRule(j));
        }
    }
}
